Cypress 2
JeongSeulho
2024년 01월 27일
준비중...
클립보드로 복사
0. 들어가며
Cypress
를 통한 E2E 테스트에 대해 정리 2편
1. 커스텀 커맨드와 커스텀 쿼리
반복 로직을 명령으로 만들고 사용하는 기능이다, 주로 다음과 같은 상황에서 사용
- 동일한 요소를 반복해서 조회
- 동일한 내용을 반복해서 검증
- 테스트 구동을 위한 환경 설정(로그인 등)
(1) 커스텀 커맨드
- retry ability 미지원
- 비동기 동작 가능
(2) 커스텀 쿼리
- retry ability 지원
- 동기적으로 동작
- subject를 받아 내부적으로 체이닝 코드 재시도
(3) 커스텀 커맨드와 커스텀 쿼리의 예시
- 작성 예시
// cypress/support/commands.js
import '@testing-library/cypress/add-commands';
// 로그인 커스텀 커맨드
Cypress.Commands.add('login', () => {
const username = 'maria@mail.com';
const password = '12345';
// 쿠키, 로컬 스토리지, 세션 스토리지에 있는 정보들을 캐싱
cy.session(username, () => {
cy.visit('/login');
cy.findByLabelText('이메일').type(username);
cy.findByLabelText('비밀번호').type(password);
cy.findByLabelText('로그인').click();
// 캐싱하기 전에 로그인이 성공했는지 확인
cy.location('pathname').should('eq', '/');
});
// 로그인 이후 메인 홈페이지로 이동
cy.visit('/');
});
// 로그아웃 커스텀 커맨드
Cypress.Commands.add('logout', () => {
cy.findByRole('button', { name: 'Maria' }).click();
cy.findByRole('button', { name: '확인' }).click();
});
// 현재 URL 단언 커스텀 커맨드
Cypress.Commands.add('assertUrl', url => {
cy.url().should('eq', `${Cypress.env('baseUrl')}${url}`);
});
// 특정 인덱스의 상품 카드를 가져오는 커스텀 커맨드
Cypress.Commands.add('getProductCardByIndex', index => {
return cy.findAllByTestId('product-card').eq(index);
});
// 장바구니 버튼을 가져오는 커스텀 쿼리
Cypress.Commands.addQuery('getCartButton', () => {
// 비동기이기 때문에 cy.now()로 쿼리(get)을 감싼 후 사용하면 inner function에서 사용 가능
const getFn = cy.now('get', `[data-testid="cart-icon"]`);
// inner function을 리턴하는 형태로 콜백을 사용
// 체이닝을 위해 subject를 인자로 받음
return subject => {
// data-testid="cart-icon" 요소를 조회하는 get 쿼리
// subject 기준으로
const btn = getFn(subject);
return btn;
};
});
- 사용 예시
it('성공적으로 로그인 되었을 경우 메인 홈 페이지로 이동하며, 사용자 이름 "Maria"와 장바구니 아이콘이 노출된다', () => {
// 로그인 커스텀 커맨드 사용
cy.login();
// 현재 URL 단언 커스텀 커맨드 사용
cy.assertUrl('/');
cy.findByText('Maria').should('exist');
cy.findByTestId('cart-icon').should('exist');
});
describe('로그인 시', () => {
// cy.session을 사용하여 처음 로그인을 한번만 수행하면 이후로 캐싱하여 사용
beforeEach(() => {
cy.login();
});
...
});
2. E2E 테스트에서 모킹
회원가입을 테스트 할 때, 몇 가지 문제가 발생
- 이전의 가입한 테스트 계정과 매번 중복되지 않는 계정을 생성해야 함
- 계속 가입을 하다보면 DB에 불필요한 데이터가 쌓임
이러한 문제로 인하여 회원가입과 탈퇴를 같이 한 프로세스로 테스트하는 것이 좋으나 회원가입만 성공하고 탈퇴가 실패하는 경우가 있을 수 있음
이렇게 불가피한 경우 cy.intercept
로 모킹하여 테스트를 진행
이외에도 다양한 상황에서 모킹을 사용할 수 있음
(1) E2E 테스트에서 모킹을 사용하는 경우
- 실패 케이스를 테스트하는 경우
- 서드파티 API 또는 외부 서비스를 사용하는 경우
- DB에 영향을 주는 경우
(2) cy.intercept 사용 예시
it('성공적으로 회원 가입이 완료되었을 경우 "가입 성공!"문구가 노출되며 로그인 페이지로 이동한다', () => {
cy.intercept('POST', 'http://localhost:3000/users', { statusCode: 200 });
cy.findByLabelText('이름').type('hanjung');
cy.findByLabelText('이메일').type('han@email.com');
cy.findByLabelText('비밀번호').type('password123');
cy.findByText('가입').click();
cy.findByText('가입 성공!').should('exist');
cy.assertUrl('/login');
});
it('회원 가입이 실패했을 경우 "잠시 문제가 발생했습니다! 다시 시도해 주세요." 문구가 노출된다', () => {
cy.intercept('POST', 'http://localhost:3000/users', { statusCode: 401 });
cy.findByLabelText('이름').type('hanjung');
cy.findByLabelText('이메일').type('han@email.com');
cy.findByLabelText('비밀번호').type('password123');
cy.findByText('가입').click();
cy.findByText('잠시 문제가 발생했습니다! 다시 시도해 주세요.').should(
'exist',
);
});
3. cypress Github Action에 적용하기
# .github/workflows/cypress.yml
name: 'Cypress Tests'
on: push
jobs:
cypress-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 19
- name: Install dependencies
run: npm ci
- name: Cypress run
uses: cypress-io/github-action@v5
with:
build: npm run build
start: npm run dev